﻿using Sgr.EventBus.RelayBoxs.Domain;
using Sgr.Utilities;

namespace Sgr.EventBus.RelayBoxs.Services
{
    /// <summary>
    /// 基于“发件箱模式”的事件总线实现，负责将集成事件保存到发件箱表中，以便后续可靠地发布到消息队列或其他消费者。
    /// </summary>
    public class OutboxEventBus : IEventBus
    {
        private const string TOPIC = "sgr";
        private readonly IOutboxMessageRepository _outboxMessageRepository;

        /// <summary>
        /// 构造函数，通过依赖注入接收发件箱消息仓储接口的实现。
        /// </summary>
        /// <param name="outboxMessageRepository">用于操作发件箱消息存储的仓储接口</param>
        public OutboxEventBus(IOutboxMessageRepository outboxMessageRepository)
        {
            _outboxMessageRepository = outboxMessageRepository ?? throw new ArgumentNullException(nameof(outboxMessageRepository));
        }

        /// <summary>
        /// 异步发布一个集成事件，将其保存到发件箱中。
        /// </summary>
        /// <param name="event">要发布的集成事件对象</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>表示异步操作的任务</returns>
        public Task PublishAsync(IntegrationEvent @event, CancellationToken cancellationToken = default)
        {
            // 获取事件类型的程序集限定名称，用于标识事件类型

            //// 稳健的后备：优先 FullName，否则用短名（或自定义事件名）
            //var type = @event.GetType();
            //var messageType = type.FullName ?? type.Name;

            var messageType = IntegrationEventTypes.ResolveTypeName(@event.GetType());// @event.GetType().AssemblyQualifiedName!;

            // 将事件对象序列化为 JSON 格式的字符串，作为消息负载
            string payload = JsonHelper.SerializeObject(@event);

            // 创建一个发件箱消息对象
            var outboxMessage = new OutboxMessage(TOPIC, messageType, @event.Id, payload);

            // 将构造好的发件箱消息异步保存到存储中（如数据库）
            return _outboxMessageRepository.InsertAsync(outboxMessage, cancellationToken);
        }
    }
}